﻿using System.Reflection;

namespace CTP.CRM.Core.Configuration.AutoRegistOptions
{
    public static class OptionsStartupExtensions
    {
        //
        // 摘要:
        //     自动注入Options 规则： 必须继承至IOptionAutoInjection 配置名称与Option类名必须对应上：例如json配置文件中有一节点【Kestrel】会自动注入到【KestrelOptions】类中，大小写敏感
        //
        //
        // 参数:
        //   webBuilder:
        //
        //   assemblyWhere:
        //     程序集过滤器
        //
        // 异常:
        //   T:System.Exception:
        public static WebApplicationBuilder AddOptionsFromConfiguration(this WebApplicationBuilder webBuilder, Func<Assembly, bool>? assemblyWhere = null)
        {
            // 获取WebApplicationBuilder的配置管理器
            ConfigurationManager configuration = webBuilder.Configuration;
            // 根据提供的条件过滤程序集
            IEnumerable<Assembly> assembliesByFilter = PublicTools.GetAssembliesByFilter(assemblyWhere);
            // 遍历每个筛选后的程序集
            foreach (Assembly item in assembliesByFilter)
            {
                IEnumerable<Type> enumerable;
                try
                {
                    // 查找所有实现了IOptionAutoInjection接口的非抽象类型
                    enumerable = from type in item.GetTypes()
                                 where typeof(IOptionAutoInjection).IsAssignableFrom(type) && !type.GetTypeInfo().IsAbstract
                                 select type;
                }
                catch
                {
                    // 如果获取类型时发生异常，则跳过该程序集
                    continue;
                }

                // 遍历每个找到的类型
                foreach (Type item2 in enumerable)
                {
                    // 根据类型名称从配置中获取相应的配置节（移除“Options”后缀）
                    IConfigurationSection section = configuration.GetSection(item2.Name.Replace("Options", ""));
                    MethodInfo method = typeof(OptionsConfigurationServiceCollectionExtensions).GetMethod("Configure", new Type[2]
                    {
                    typeof(IServiceCollection),
                    typeof(IConfiguration)
                    });
                    // 创建Configure方法的泛型版本，使用当前类型作为泛型参数
                    MethodInfo methodInfo = method.MakeGenericMethod(item2);
                    // 调用Configure方法，将服务集合和配置节作为参数传递
                    methodInfo.Invoke(null, new object[2] { webBuilder.Services, section });
                }
            }

            return webBuilder;
        }
    }
}
